package com.doumuxie.handler;

import com.doumuxie.util.DataUtil;
import com.sun.org.apache.xpath.internal.operations.Bool;

import java.util.Arrays;

/**
 * @author doumuxie https://gitee.com/doumuxie/
 * @version 1.0
 * @date 2020年11月5日17:21:31
 * @description 银行家算法相关
 **/
public class BankHandler {

    /**
     * 5 个进程
     */
    public static int count = 5;

    public static Integer[][] max = new Integer[100][100];

    public static Integer[][] allocation = new Integer[100][100];

    public static Integer[][] need = new Integer[100][100];

    public static Integer[] available = new Integer[100];

    public static Integer[] request = new Integer[100];

    public static void initData() {
        max = new Integer[][]{{7, 5, 3}, {3, 2, 2}, {9, 0, 2}, {2, 2, 2}, {4, 3, 3}};
        allocation = new Integer[][]{{0, 1, 0}, {2, 0, 0}, {3, 0, 2}, {2, 1, 1}, {0, 0, 2}};
        need = new Integer[][]{{7, 4, 3}, {1, 2, 2}, {6, 0, 0}, {0, 1, 1}, {4, 3, 1}};
        available = new Integer[]{3, 3, 2};
        request = new Integer[]{1, 0, 2};
    }

    public static void main(String[] args) {
        // 初始化数据
        initData();
        // 模拟P1发出请求向量
        int requestIndex = 1;
        // 判断 Request <= Need 小于等于 need （需要的）
        if (!isLess(request, need[requestIndex])) {
            System.err.println("不安全");
            return;
        }
        // 判断Request <= available 小于等于 available（可用）
        if (!isLess(request, available)) {
            System.err.println("不安全");
            return;
        }
        // 假定分配资源 并修改 available allocation need值， 在使用安全算法进行校
        boolean isSafe = safeCheck(requestIndex, available, allocation, need, request);
        if (isSafe) {
            System.out.println("安全");
        } else {
            System.err.println("不安全");
        }
    }

    private static boolean safeCheck(int requestIndex, Integer[] available, Integer[][] allocation, Integer[][] need, Integer[] request) {
        // 复制数据 尝试分配资源
        Integer[][] maxTemp = DataUtil.copyArray(max);
        Integer[][] allocationTemp = DataUtil.copyArray(allocation);
        Integer[][] needTemp = DataUtil.copyArray(need);
        Integer[] availableTemp = DataUtil.copyArray(available);
        // Available［j］∶=Available［j］-Requesti［j］;
        arrayCut(availableTemp, request);
        //  Allocation［i,j］∶=Allocation［i,j］+Requesti［j］;
        arrayAdd(allocationTemp[requestIndex], request);
        //  Need［i,j］∶=Need［i,j］-Requesti［j］;
        arrayCut(needTemp[requestIndex], request);
        // 执行安全性算法
        Integer[] workTemp = DataUtil.copyArray(availableTemp);
        // 默认都为 false
        boolean[] finish = new boolean[maxTemp.length];
        while (true) {
            // 从进程集合中找到一个能满足下述条件的进程：
            //    ① Finish［i］=false;
            //    ② Need［i,j］≤Work［j］； 若找到， 执行步骤(3)， 否则，执行步骤(4)。
            int i;
            for (i = 0; i < finish.length; i++) {
                if ((!finish[i]) && isLess(needTemp[i], workTemp)) {
                    // 执行步骤(3)
                    arrayAdd(workTemp, allocationTemp[i]);
                    finish[i] = true;
                    break;
                }
            }
            if (i >= finish.length) {
                break;
            }
        }
        for (boolean b : finish) {
            if (!b) {
                return false;
            }
        }
        return true;
    }

    /**
     * 数组相加 结果存放第一个数组
     *
     * @param source source
     * @param temp   temp
     */
    private static void arrayAdd(Integer[] source, Integer[] temp) {
        for (int i = 0; i < source.length; i++) {
            source[i] += temp[i];
        }
    }

    /**
     * 数组相减 结果存放第一个数组
     *
     * @param source source
     * @param temp   temp
     */
    private static void arrayCut(Integer[] source, Integer[] temp) {
        for (int i = 0; i < source.length; i++) {
            source[i] -= temp[i];
        }
    }


    /**
     * min 小于等于 max
     *
     * @param min min
     * @param max max
     * @return
     */
    private static boolean isLess(Integer[] min, Integer[] max) {
        for (int i = 0; i < min.length; i++) {
            if (min[i] > max[i]) {
                return false;
            }
        }
        return true;
    }

}
